# -*- coding: utf-8 -*-
"""

"""

from docutils import nodes

from sphinx.locale import _
from sphinx.environment import NoUri
from sphinx.util.nodes import set_source_info
from sphinx.util.compat import Directive, make_admonition
from docutils.parsers.rst import directives
from docutils.statemachine import ViewList

class swe_node(nodes.Admonition, nodes.Element): pass
class swelist(nodes.General, nodes.Element): pass

swe_vmap={}

class BasicSwe(Directive):
    """
    A FRS entry, displayed (if configured) in the form of an admonition.
    """
    has_content = True
    required_arguments = 1
    optional_arguments = 20
    final_argument_whitespace = False
    option_spec = {
        'disable': directives.nonnegative_int,
        'parent': directives.unchanged_required
    }
    keyword = 'SWE'

    def run(self):
        """
         @brief 如果以keyword开头，则进行编号，否则按照默认编号
         第一行包含在arguments中，后续段落包含在contents中

         此处的env是文档内部的env
        """
        env = self.state.document.settings.env

        #print self.block_text, self.content
        mc = self.content
        starti = 0
        title = self.arguments[0].upper()
        if title.startswith(self.keyword):
            targetid = directives.unchanged(title)
            starti += 1
        else:
            targetid = self.keyword+'%s' % env.new_serialno(self.keyword)

        self.options['id'] = targetid

        global swe_vmap
        if self.options.has_key('parent'):
            print '==Get parent %s for %s'%(self.options['parent'].upper(), targetid)
            #env.swe_vmap[targetid] = self.options['parent'].upper()
            if swe_vmap.has_key(targetid):
                raise KeyError, 'Dumplicate id %s'%targetid
            swe_vmap[targetid] = self.options['parent'].upper()

        if len(self.arguments) >= 1:
            if len(self.content) > 0:
                self.content.insert(0, ViewList(self.arguments[starti:]))
            else:
                mc = ViewList(self.arguments[starti:])

        targetnode = nodes.target('', '', ids=[targetid])

        ad = make_admonition(swe_node, self.name, [targetid], self.options,
                             mc, self.lineno, self.content_offset,
                             self.block_text, self.state, self.state_machine)
        set_source_info(self, ad[0])

        if self.options.has_key('disable') and self.options['disable'] != 0:
            pass

        return [targetnode] + ad

class Frs(BasicSwe):
    keyword='FRS'

class Swrs(BasicSwe):
    keyword='SWRS'

class ArchDesign(BasicSwe):
    keyword='ARCHD'

class DetailedDesign(BasicSwe):
    keyword='DETAILD'

class FunctionTest(BasicSwe):
    keyword='FTEST'


class SweList(Directive):
    """
    A list of all todo entries.
    """

    has_content = False
    required_arguments = 0
    optional_arguments = 0
    final_argument_whitespace = False
    option_spec = {}

    def run(self):
        return [swelist('')]


def process_swes(app, doctree):
    env = app.builder.env
    global swe_vmap
    if not hasattr(env, 'swe_all_nodes'):
        env.swe_all_nodes = []
        env.swe_all_vmap = swe_vmap

    for node in doctree.traverse(swe_node):
        try:
            targetnode = node.parent[node.parent.index(node) - 1]
            if not isinstance(targetnode, nodes.target):
                raise IndexError
        except IndexError:
            targetnode = None
        newnode = node.deepcopy()
        ids = newnode['ids']
        refid = targetnode['refid']

        del newnode['ids']
        env.swe_all_nodes.append({
            'docname': env.docname,
            'source': node.source or env.doc2path(env.docname),
            'lineno': node.line,
            'elem': newnode,
            'target': targetnode,
        })
        print "==swe adding ids", ids


def process_swe_nodes(app, doctree, fromdocname):
    if not app.config['swe_include_frs']:
        for node in doctree.traverse(swe_node):
            node.parent.remove(node)

    # Replace all todolist nodes with a list of the collected todos.
    # Augment each todo with a backlink to the original location.
    env = app.builder.env

    if not hasattr(env, 'swe_all_nodes'):
        env.swe_all_nodes = []

    # 最后一步，需要打印具备交叉索引的所有文件
    for node in doctree.traverse(swelist):
        if not app.config['swe_include_frs']:
            node.replace_self([])
            continue

        content = []

        for elem in env.swe_all_nodes:
            para = nodes.paragraph(classes=['todo-source'])
            refid = elem['target']['refid']

            description = _('(The <<original entry>> is located in '
                            ' %s, line %d. %s)') % \
                          (elem['source'], elem['lineno'], 
                           refid)
            desc1 = description[:description.find('<<')]
            desc2 = description[description.find('>>')+2:]
            para += nodes.Text(desc1, desc1)

            # Create a reference
            newnode = nodes.reference('', '', internal=True)
            #innernode = nodes.emphasis(_('original entry'), _('original entry'))
            innernode = nodes.emphasis(refid, refid)
            try:
                newnode['refuri'] = app.builder.get_relative_uri(
                    fromdocname, elem['docname'])
                newnode['refuri'] += '#' + refid
            except NoUri:
                # ignore if no URI can be determined, e.g. for LaTeX output
                pass
            newnode.append(innernode)
            para += newnode
            para += nodes.Text(desc2, desc2)

            # (Recursively) resolve references in the todo content
            todo_entry = elem['elem']
            env.resolve_references(todo_entry, elem['docname'],
                                   app.builder)

            # Insert into the todolist
            content.append(todo_entry)
            content.append(para)

        node.replace_self(content)


def purge_swes(app, env, docname):
    if not hasattr(env, 'swe_all_nodes'):
        return
    env.swe_all_nodes = [e for e in env.swe_all_nodes
                          if e['docname'] != docname]
    #print "map of all nodes:", env.swe_vmap
    #print "Get all elem vmap:", swe_vmap

def visit_swe_node(self, node):
    self.visit_admonition(node)


def depart_swe_node(self, node):
    self.depart_admonition(node)


def setup(app):
    app.add_config_value('swe_include_frs', False, 'html')

    app.add_node(swelist)
    app.add_node(swe_node,
                 html=(visit_swe_node, depart_swe_node),
                 latex=(visit_swe_node, depart_swe_node),
                 text=(visit_swe_node, depart_swe_node),
                 man=(visit_swe_node, depart_swe_node),
                 texinfo=(visit_swe_node, depart_swe_node))
    app.add_directive('frs', Frs)
    app.add_directive('swrs', Swrs)
    app.add_directive('swelist', SweList)
    app.connect('doctree-read', process_swes)
    app.connect('doctree-resolved', process_swe_nodes)
    app.connect('env-purge-doc', purge_swes)

